#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/limits.h>
#include <linux/string.h>
#include <linux/file.h>
#include <linux/fs.h>
#include <linux/net.h>
#include <linux/pagemap.h>
#if defined(TK4) || defined(TK4_NEW)
#include <linux/genhd.h>
#else
#include <linux/blkdev.h>
#endif
#include <net/sock.h>
#include <target/target_core_base.h>
#include "kprobe_prehook.h"
#include "syms.h"
#include "./include/kernel/sched/sched.h"
#include "./include/drivers/target/target_core_file.h"
#include "./include/drivers/block/loop.h"

#define shm_file_data(file) (*((struct shm_file_data **)&(file)->private_data))
extern unsigned int sysctl_module_debug;
struct shm_file_data {
    int id;
    struct ipc_namespace *ns;
    struct file *file;
    const struct vm_operations_struct *vm_ops;
};
struct address_space *folio_mapping_ftrace(struct folio *folio)
{
    struct address_space *mapping;

    /* This happens if someone calls flush_dcache_page on slab page */
    if (unlikely(folio_test_slab(folio)))
        return NULL;

    if (unlikely(folio_test_swapcache(folio)))
        return NULL;

    mapping = folio->mapping;
    if ((unsigned long)mapping & PAGE_MAPPING_FLAGS)
        return NULL;

    return mapping;
}

bool sub_print_func_name(void *opt, void *opt2, void *opt3, char *pointer, char *func)
{
	bool ret = true;


	if ((check_func_name("nobh_truncate_page") || check_func_name("do_read_cache_page") || check_func_name("read_pages"))
		&& strstr(pointer, "mapping->a_ops->read_folio")) {
		struct address_space *mapping = (struct address_space *)opt;
		sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->read_folio);
		return ret;
	}
	if ((check_func_name("generic_file_buffered_read")) && strstr(pointer, "mapping->a_ops->read_folio")) {
		struct kiocb *iocb = (struct kiocb *)opt;
		struct file *filp = iocb->ki_filp;
		struct address_space *mapping = filp->f_mapping;
		sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->read_folio);
		return ret;
	}
	if ((check_func_name("filemap_fault")) && strstr(pointer, "mapping->a_ops->read_folio")) {
		struct vm_fault *vmf = (struct vm_fault *)opt;
		struct file *file = vmf->vma->vm_file;
		struct address_space *mapping = file->f_mapping;
		sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->read_folio);
		return ret;
	}
	if ((check_func_name("filemap_fault")) && strstr(pointer, "mapping->a_ops->read_folio")) {
		struct vm_fault *vmf = (struct vm_fault *)opt;
		struct file *file = vmf->vma->vm_file;
		struct address_space *mapping = file->f_mapping;
		sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->read_folio);
		return ret;
	}
	if ((check_func_name("read_pages")) && strstr(pointer, "ops->readahead")) {
		struct readahead_control *rac = (struct readahead_control *)opt;
		const struct address_space_operations *aops = rac->mapping->a_ops;
		if (rac && aops->readahead)
			sprintf(func, FUNCTION_PRINT_FORMAT, aops->writepage);
		return ret;
	}
	if ((check_func_name("folio_invalidate")) && strstr(pointer, "a_ops->invalidate_folio")) {
		struct folio *folio = (struct folio *)opt;
		const struct address_space_operations *aops = folio->mapping->a_ops;
		if (aops->invalidate_folio)
			sprintf(func, FUNCTION_PRINT_FORMAT, aops->invalidate_folio);
		return ret;
	}
	if ((check_func_name("filemap_release_folio")) && strstr(pointer, "mapping->a_ops->release_folio")) {
		struct folio *folio = (struct folio *)opt;
		struct address_space * const mapping = folio->mapping;
		if (mapping && mapping->a_ops->release_folio)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->release_folio);
		return ret;
	}
	if ((check_func_name("move_to_new_folio")) && strstr(pointer, "mapping->a_ops->migrate_folio")) {
		struct folio *src = (struct folio *)opt2;
		struct address_space *mapping = folio_mapping_ftrace(src);
		if (mapping && mapping->a_ops->migrate_folio)
			sprintf(func, FUNCTION_PRINT_FORMAT, mapping->a_ops->migrate_folio);
		return ret;
	}
	if (strstr(pointer, "rq->curr->sched_class->wakeup_preempt")) {
		struct rq *rq = (struct rq *)opt;
		sprintf(func, FUNCTION_PRINT_FORMAT, rq->curr->sched_class->wakeup_preempt);
		return ret;
	}

	return false;
}
